#pragma once

#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include <functional>

#include "../common/net.hpp"
#include "../common/message.hpp"

namespace JsonMuduoRPC
{
    namespace server
    {
        enum class VType
        {
            BOOL = 0, // 布尔类型
            INTEGRAL, // 整形
            NUMERIC,  // 浮点型
            STRING,   // 字符出类型
            ARRAY,    // 数组类型
            OBJECT    // JSON对象类型
        };

        // 服务描述类
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using ServiceCallBack = std::function<void(const Json::Value &, Json::Value &)>;
            using ParamsDescribe = std::pair<std::string, VType>;

            ServiceDescribe(std::string &&service_name, ServiceCallBack &&cb_service,
                            std::vector<ParamsDescribe> &&params_desc, VType result_type)
                : _service_name(std::move(service_name)),
                  _cb_service(std::move(cb_service)),
                  _params_desc(std::move(params_desc)),
                  _result_type(result_type) {}

            std::string getServiceName() { return _service_name; }

            // 参数校验
            bool paramCheak(const Json::Value &params)
            {
                for (auto &desc : _params_desc)
                {
                    if (params.isMember(desc.first) == false)
                    {
                        LOG(ERROR, "参数完整性校验失败：%s", desc.first);
                        return false;
                    }
                    if (cheakType(desc.second, params[desc.first]) == false)
                    {
                        LOG(ERROR, "参数%s类型检验失败", desc.first);
                        return false;
                    }
                }

                return true;
            }

            // 调用服务回调
            bool call(const Json::Value &params, Json::Value &result)
            {
                _cb_service(params, result);
                if (cheakResultType(result) == false)
                {
                    LOG(ERROR, "返回结果类型校验失败");
                    result = Json::Value();
                    return false;
                }
                return true;
            }

        private:
            // 返回值类型校验
            bool cheakResultType(const Json::Value &result)
            {
                return cheakType(_result_type, result);
            }
            bool cheakType(const VType &type, const Json::Value &val)
            {
                switch (type)
                {
                case VType::BOOL:
                    return val.isBool();
                case VType::INTEGRAL:
                    return val.isIntegral();
                case VType::NUMERIC:
                    return val.isNumeric();
                case VType::STRING:
                    return val.isString();
                case VType::ARRAY:
                    return val.isArray();
                case VType::OBJECT:
                    return val.isObject();
                default:
                    return false;
                }
            }

        private:
            std::string _service_name;                // 服务名称
            ServiceCallBack _cb_service;              // 提供具体服务的回调
            std::vector<ParamsDescribe> _params_desc; // 参数描述集合
            VType _result_type;                       // 返回结果类型
        };

        // 因为ServiceDescribe的成员需要从外部设置
        // 为了保证线程安全，需要在创建ServiceDescribe对象的时候就要将其属性设置好
        // 这里就可以采用工厂的建造build模式
        class ServiceDescribeFactory
        {
        public:
            void setServiceName(const std::string &service_name) { _service_name = service_name; }
            void setServiceCallBack(const ServiceDescribe::ServiceCallBack &cb_service) { _cb_service = cb_service; }
            void setParamsDescribe(const std::string &param, const VType &type) { _params_desc.push_back(std::make_pair(param, type)); }
            void setResultType(const VType &type) { _result_type = type; }

            ServiceDescribe::ptr bulid()
            {
                return std::make_shared<ServiceDescribe>(std::move(_service_name), std::move(_cb_service),
                                                         std::move(_params_desc), _result_type);
            }

        private:
            std::string _service_name;                                 // 服务名称
            ServiceDescribe::ServiceCallBack _cb_service;              // 提供具体服务的回调
            std::vector<ServiceDescribe::ParamsDescribe> _params_desc; // 参数描述集合
            VType _result_type;                                        // 返回结果类型
        };

        class ServiceManager
        {
        public:
            using ptr = std::shared_ptr<ServiceManager>;

            void insert(const ServiceDescribe::ptr &service)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _service_map.insert(std::make_pair(service->getServiceName(), service));
            }

            void remove(const std::string &service_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _service_map.erase(service_name);
            }

            ServiceDescribe::ptr select(const std::string &service_name)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _service_map.find(service_name);
                if (it != _service_map.end())
                    return it->second;

                return ServiceDescribe::ptr();
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, ServiceDescribe::ptr> _service_map;
        };

        class RPCRouter
        {
        public:
            using ptr = std::shared_ptr<RPCRouter>;
            RPCRouter() : _service_manager(std::make_shared<ServiceManager>()) {}

            void registerService(const ServiceDescribe::ptr &service_desc)
            {
                _service_manager->insert(service_desc);
            }
            void onRpcRequest(const BaseConnection::ptr &con, const RPCRequest::ptr &req)
            {
                // 1. 判断当前是否能够提供req的服务
                const std::string service_name = req->getMethod();
                ServiceDescribe::ptr service_desc = _service_manager->select(service_name);
                if (service_desc.get() == nullptr)
                {
                    LOG(ERROR, "%s: 服务未找到", service_name.c_str());
                    return response(con, req, Json::Value(), RCode::RCODE_NOT_FOUND_SERVICE);
                }

                // 2. 判断参数是否符合规范
                const Json::Value &params = req->getParams();
                if (service_desc->paramCheak(params) == false)
                {
                    LOG(ERROR, "%s: 参数校验失败", service_name.c_str());
                    return response(con, req, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }

                // 3. 调用服务回调对请求做处理
                Json::Value result;
                bool ret = service_desc->call(params, result);
                if (ret == false)
                {
                    LOG(ERROR, "%s: 返回类型校验失败", service_name.c_str());
                    return response(con, req, Json::Value(), RCode::RCODE_INTERNAL_ERROR);
                }

                // 4. 组织响应，进行发送
                return response(con, req, result, RCode::RCODE_OK);
            }

        private:
            void response(const BaseConnection::ptr &con,
                          const RPCRequest::ptr &rpc_req,
                          const Json::Value &result, const RCode &rcode)
            {
                RPCResponse::ptr rpc_rsp = MessageFactory::create<RPCResponse>();
                rpc_rsp->setId(rpc_req->getId());
                rpc_rsp->setMType(MType::RSP_RPC);
                rpc_rsp->setRCode(rcode);
                rpc_rsp->setResult(result);

                con->send(rpc_rsp);
            }

        private:
            ServiceManager::ptr _service_manager;
        };
    } // namespace server
}